﻿using System;
using System.Windows;
using System.Threading;
using System.IO;
using System.ComponentModel.Composition;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;

namespace WpfAppHost
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application, IDisposable
    {
        private CompositionContainer _container; 
        static internal Mutex RunningMtx;

        /// <summary>
        /// Application Entry Point.
        /// </summary>
        [STAThreadAttribute()]
        public static void Main()
        {
            bool created = false;
            RunningMtx = new Mutex(true, "Local\\C4F_MEF_UTILITY_RUNNER", out created);

            // Delete any lingering "showme" file
            string showme = Path.Combine(AddinManager.AddinsDir, "App.showme");
            try
            {
                if (File.Exists(showme)) File.Delete(showme);
            }
            catch { }

            string[] args = Environment.GetCommandLineArgs();

            // Treat arguments as addins to install
            if (args.Length > 1)
            {
                // Copy addins so they can be picked up
                for (int idx = 1; idx < args.Length; idx++)
                    TriggerAddinInstall(args[idx]);
            }

            if (created) // new instance!
            {
                new App().Run();
                GC.KeepAlive(RunningMtx);
            }
            else
            {
                // Launched without args -- just double-clicking
                File.Create(showme).Close();
            }
        }

        [Import("MainWindow")]
        public new Window MainWindow
        {
            get { return base.MainWindow; }
            set { base.MainWindow = value; }
        }

        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);
            Compose();
            (MainWindow as MainAppWindow).Init();
        }

        protected override void OnExit(ExitEventArgs e)
        {
            base.OnExit(e);
        }

        public void Compose()
        {
            string AddinsDir = System.IO.Path.Combine(Environment.CurrentDirectory, "addins");

            var _catalog = new AggregateCatalog();

            if (_catalog.Catalogs.Count == 0)
            {
                // Check for exports in the main assembly
                _catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));

                _container = new CompositionContainer(_catalog);
            }
            
            // Map the imports to the exports including the AddinManager
            // and the Application object
            CompositionBatch batch = new CompositionBatch();
            batch.AddPart(this);

            // This line might throw an exception, but we'll let it go since it
            // would be catastrophic anyway
            _container.Compose(batch);

        }

        static bool TriggerAddinInstall(string path)
        {
            // Be sure that this is a valid file first...
            if (!File.Exists(path))
            {
                MessageBox.Show("You passed an addin filename to install which does not exist.", "Missing addin file");
                return false;
            }
            else if (!path.EndsWith(".util") && !path.EndsWith(".UTIL"))
            {
                MessageBox.Show("You passed an addin filename to install, but the file does not appear to be an addin.", "Invalid addin filename");
                return false;
            }

            // Now get ready to rename and copy files as needed
            string AddinsDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "MefUtilRunner\\Addins");
            string dest = Path.Combine(AddinsDir, Path.GetFileName(path));

            // If file is already there, then it's been copied but not yet installed
            // Either user tried to add again by mistake, or perhaps this is newer.
            if (File.Exists(dest))
                File.Delete(dest);

            if (File.Exists(dest + ".update"))
                File.Delete(dest + ".update");

            if(Directory.Exists(dest))
            {
                // If directory exists, this addin is installed so the supplied one
                // should be treated as an update
                File.Copy(path, dest + ".update");
            }
            else
            {
                // Either .util is already there (not yet installed), or this is brand-new
                File.Copy(path, dest);
            }

            return true;
        }

        public void Dispose()
        {
            if (this._container != null)
            {
                this._container.Dispose();
            }
        }
    }
}
